Skip to content

feat(sync): Phase 1 porter workflow + enriched icon/color maps - #67

Closed
IgorShevchik wants to merge 2 commits into
mainfrom
claude/sync-phase1-porter
Closed

feat(sync): Phase 1 porter workflow + enriched icon/color maps#67
IgorShevchik wants to merge 2 commits into
mainfrom
claude/sync-phase1-porter

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Summary

Phase 1 of the nuxt/ui → b24ui sync pipeline (see .sync/PLAN.md). Adds the manual porter workflow plus the maps it relies on. Nothing runs automatically — the workflow is workflow_dispatch only and does not advance the ledger cursor.

What's included

.github/workflows/sync-porter.yml — ports ONE upstream commit:

  1. Validate the SHA (^[0-9a-f]{40}$).
  2. Fetch the nuxt/ui commit, write its diff to a file (hard-fail if the SHA is gone — force-push guard).
  3. Branch sync/nuxt-<short> off main (deletes any abandoned branch first).
  4. Run Claude (anthropics/claude-code-action@v1) — it reads .sync/PORTING.md (rules) and the untrusted diff file, and reproduces the change under src/ only. Tools limited to Read,Edit,Write,Grep,Glob (no Bash → it can't run git/secrets).
  5. Scope guard — fail if anything outside src//test//.sync/log/ changed.
  6. Security gate — new v-html/innerHTMLsecurity-review-required label.
  7. No-op detection — docs/deps/infra commits write a one-line rationale to .sync/log/<sha>.md instead.
  8. Gates in ci.yml order: dev:prepare → lint → typecheck → test run -u → test run → build.
  9. Commit (Upstream: nuxt/ui@<sha> trailer) and open a PR labelled nuxt-sync with an <!-- upstream-sha --> footer.

Maps (now grounded, not stubs):

  • icon-map.json — 33 literal i-lucide-*b24-icons entries, verified against src/runtime/dictionary/icons.ts.
  • color-map.json — nuxt tokens → air-*, verified against src/theme/*.ts.

PORTING.md — documents the key insight: b24ui shares nuxt/ui's semantic icon keys (icons.chevronDown, …), so most icon references port 1:1; the map is only the fallback for hardcoded literals.

Before this can actually run (blockers)

Out of scope

  • Phase 2 (dispatcher/queue) and Phase 3 (cursor advance) — later milestones.

https://claude.ai/code/session_01Qz7EXMncvEGiCj4WbmYgJo


Generated by Claude Code

claude added 2 commits June 5, 2026 14:06
- .github/workflows/sync-porter.yml: manual (workflow_dispatch) porter that
  ports ONE nuxt/ui commit via Claude, with SHA validation, untrusted-diff
  isolation, a src/-only scope guard, a v-html security gate, no-op detection,
  the full ci gate chain, and PR creation. Experimental; needs ANTHROPIC_API_KEY;
  does not advance the cursor.
- icon-map.json: grounded literal lucide -> b24-icons map (verified against
  src/runtime/dictionary/icons.ts).
- color-map.json: nuxt tokens -> air-* (verified against src/theme).
- PORTING.md: document that the semantic icons.<key> interface is shared, so
  most icon references port 1:1 and the map is only for hardcoded literals.
Switch the porter's Claude auth from anthropic_api_key to
claude_code_oauth_token (Pro/Max subscription, via `claude setup-token`), and
add a max_turns workflow input so trial runs can be capped lower.

Copy link
Copy Markdown
Collaborator Author

Closing: the sync is manual by decision, so sync-porter.yml will not land. #377 removes the rest of the automation — .sync/PLAN.md, .sync/RUNBOOK.md, the sync_enabled kill-switch and the never-written stats block — and writes the manual procedure into PORTING.md §6 in their place.

Recording what is in this branch that the workflow file is not, so it is not lost:

  1. An icons note for PORTING.md §1. b24ui shares nuxt/ui's semantic icon keys (src/runtime/dictionary/icons.ts), so appConfig.ui.icons.<key> ports unchanged; icon-map.json is only the fallback for hardcoded i-lucide-* literals. That distinction is worth having in the guide regardless of how ports are driven.
  2. icon-map.json — ~31 added entries and 5 corrections (i-lucide-checkCheckLIcon rather than CheckIcon, chevron-downChevronDownLIcon rather than ChevronDownSIcon, minusMinus30Icon, xCrossMIcon).
  3. color-map.json — the warning correction. That one is already fixed in chore(sync): make the manual sync the only sync #377: the committed map pointed warning at air-primary-alert, the same token as error, so it was telling porters the two upstream colors are interchangeable.

Items 1 and 2 are not carried over yet. Those values were written in June against an older @bitrix24/b24icons-vue and each needs checking against the installed package before it can be trusted, so folding them into a removal PR would have mixed verified deletions with unverified additions. They are listed in #377's description as an open follow-up — happy to verify and land them as their own PR.

The branch stays, so nothing here is unrecoverable.


Generated by Claude Code

IgorShevchik added a commit that referenced this pull request Aug 13, 2026
…ard it (#378)

* chore(sync): derive `icon-map.json` from the shared icon keys, and guard it

Verifies and lands the icon-map content from the closed PR #67, rebuilt rather
than imported.

The map is now **derived**. b24ui and nuxt/ui define the same semantic icon
keys — `src/runtime/dictionary/icons.ts` here, `src/theme/icons.ts` upstream —
so for each of the 37 keys both sides carry, the entry is (upstream's lucide
name -> b24ui's component). Nothing is chosen by eye.

That turned up three wrong values in #67, none of which would have failed an
import because each resolves to a real icon:

- `i-lucide-rotate-cw` where upstream's `reload` is `i-lucide-rotate-ccw`
- `i-lucide-circle-check` for `copyCheck`, whose lucide name is
  `i-lucide-copy-check` (`circle-check` is upstream's `success`, a key we do
  not have)
- `i-lucide-refresh-cw`, which no upstream key uses

and seven derivable pairs it had missed: `drag`, `panelClose`, `panelOpen`,
`star`, `stop`, `copyCheck`, `reload`.

The five entries #67 dropped (`activity`, `arrow-up-to-line`, `house`,
`settings`, `user`) are kept — they match no key on either side, which is
exactly the hardcoded-literal case this table exists for.

#67's five corrections to the committed values are confirmed: `check`,
`chevronDown`, `chevronUp`, `minus` and `x` all pointed at glyphs this library
does not render for those roles.

`test/utils/icon-map.spec.ts` holds the result: every value must resolve in the
installed `@bitrix24/b24icons-vue`, must come from the dictionary (or a
five-entry documented exception list), and must not pick the wrong group for a
name the dictionary already places — 233 icon names exist in more than one
group and 16 of those are in this map, so `solid/RefreshIcon` for
`outline/RefreshIcon` is a live failure mode, not a hypothetical.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb

* fix(sync): correct the icon-map's claims, and give its guard teeth

Review follow-up on this branch. Three of the findings were substantive.

**The recorded justification was false.** The changelog said the five corrected
values pointed at "glyphs the library does not render for those roles". It
does render them: `Checkbox.vue` renders `main/CheckIcon` and
`actions/Minus20Icon`, `Badge.vue` renders `actions/Cross20Icon`, `Button.vue`
renders `outline/ChevronDownSIcon`. Roughly half the icon paths under `src/`
are hardcoded in components that never read the dictionary. The corrections
stand — the map must agree with the dictionary — but the reason is restated,
and the underlying inconsistency is now #380.

**The guard did not check the derivation.** Pointing `i-lucide-check` at any
other icon the dictionary genuinely uses passed every assertion. There is now
an explicit `i-lucide-* -> semantic key` table, and each derived row must equal
what that key resolves to; a row disappearing fails too.

**The map was missing the one literal it exists for.** `i-lucide-terminal` is
the only `i-lucide-*` string upstream hardcodes under `src/`, and
`prose/CodeIcon.vue` has answered it all along. The old dictionary-only
allowlist would have rejected it, so the guard's basis widens to any icon used
anywhere in `src/`.

Also: `i-lucide-circle-x` gains a row (our `caution` is commented "this for
error"); the `$schema-note` no longer contradicts itself about `circle-check`;
duplicate JSON keys, which the import silently collapses, are now caught; stray
values report their key; a redundant cast is gone; and both the note and the
changelog now say the guard catches wrong rows, not stale ones.

Not changed: the 37-pair / 43x39 counts. Three reviewers read the installed
`@nuxt/ui@4.8.2` — pulled in transitively by `nuxtseo-layer-devtools`, older
than the sync cursor — and concluded `star` was fabricated. Upstream at
`3dbca02` has it. That trap is now written down.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb

---------

Co-authored-by: Shevchik Igor <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants